// Copyright (C) Kumo inc. and its affiliates.
// Author: Jeff.li lijippy@163.com
// All rights reserved.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <https://www.gnu.org/licenses/>.
//


#pragma once

#include <cantor/parser/ast/base.h>
#include <cantor/common/expr_class.h>
#include <stdlib.h>

namespace cantor::parser {
    ////////////////////////////////////////////////////////////////////////////////
    /// ExprNodeType - Enumeration of expression node types.
    ///
    /// Represents different kinds of expressions in the AST/IR,
    /// such as column references, constants, functions, rows,
    /// clauses, query blocks (DQL), data definition commands (DDL),
    /// and range variables.
    ///
    /// Example usage:
    ///   ET_FUNC      // Function call expression
    ///   ET_DQL       // Subquery or query block expression
    ////////////////////////////////////////////////////////////////////////////////

    struct Indirection;

    ////////////////////////////////////////////////////////////////////////////////
    /// DispatchExpr - Base class for expression nodes in the AST.
    ///
    /// Encapsulates the type of the expression and optional indirections
    /// (e.g., array indexing, field access).
    /// Provides serialization support to JSON and string output.
    ///
    /// Example:
    ///   DispatchExpr(ExprNodeType::ET_FUNC)     // A function call node
    ////////////////////////////////////////////////////////////////////////////////

    struct DispatchExpr : public Node {
        static constexpr cantor::pb::ast::ExprNodeClass kExprClass = cantor::pb::ast::ENC_DISPATCH;

        DispatchExpr(pb::ast::ExprNodeType t, cantor::pb::ast::ExprNodeClass c) : Node(pb::ast::NODE_TYPE_EXPR), expr_type(t),
                                                                          expr_class(pb::ast::expr_class_merge(
                                                                              kExprClass, c)) {
        }

        void to_stream(std::ostream &os) const override;

        /// The expression type identifying the specific kind of expression.
        cantor::pb::ast::ExprNodeType expr_type;
        cantor::pb::ast::ExprNodeClass expr_class;


        constexpr bool is_subquery() const {
            return expr_class & pb::ast::ENC_SUBQUERY;
        }

        constexpr bool is_exists_subquery_expr() const {
           return expr_type ==  pb::ast::ENT_EXISTS_SUB_QUERY_EXPR;
        }

        constexpr bool is_constant_expr() const {
            return expr_type ==  pb::ast::ENT_CONSTANT_EXPR;
        }

        constexpr bool is_func_expr() const {
            return expr_type == pb::ast::ENT_FUNC_EXPR;
        }

        constexpr bool is_rang_var() const {
            return expr_type == pb::ast::ENT_RANGE_VAR;
        }

        /// Append the expression node details to a JSON object.
        nlohmann::ordered_json to_json_impl() const override;
    };

    struct DefiniteExpr : public Node {
        static constexpr cantor::pb::ast::ExprNodeClass kExprClass = cantor::pb::ast::ENC_DEFINITE;

        DefiniteExpr(cantor::pb::ast::ExprNodeType t,
                     cantor::pb::ast::ExprNodeClass c) : Node(pb::ast::NODE_TYPE_DEFINITE_EXPR), expr_type(t),
                                                       expr_class(pb::ast::expr_class_merge(kExprClass, c)) {
        }

        nlohmann::ordered_json to_json_impl() const override;


        cantor::pb::ast::ExprNodeType expr_type;
        cantor::pb::ast::ExprNodeClass expr_class;
    };


    struct SelectStmt;
    struct UnionStmt;
    struct StmtNode;

    ////////////////////////////////////////////////////////////////////////////////
    /// RangeVar - Represents a range variable or table reference in expressions.
    ///
    /// This struct models identifiers that refer to tables or relations in a query,
    /// typically used in FROM clauses or as qualifiers for columns.
    /// It holds a list of names representing the hierarchy or path, such as
    /// [database, schema, table] or just [table].
    ///
    /// Example SQL:
    ///   SELECT a, b FROM mydb.myschema.mytable t WHERE t.a > 10;
    ///                      ^^^^^^^^^^^^^^^^^^^^^^^
    ///                      This part corresponds to the RangeVar,
    ///                      with names = ["mydb", "myschema", "mytable"]
    ///
    ///   The alias "t" is usually handled separately (not part of RangeVar).
    ////////////////////////////////////////////////////////////////////////////////

    struct ColumnName;

    struct RangeVar final : public DispatchExpr {
        RangeVar() : DispatchExpr(pb::ast::ExprNodeType::ENT_RANGE_VAR, cantor::pb::ast::ENC_CLAUSE) {
        }

        /// Hierarchical names for the range variable, e.g., database.schema.table
        ColumnName *column{nullptr};
        Vector<Indirection *> indirections;

        void to_stream(std::ostream &os) const override;

        /// Convert the range variable to a JSON object.
        nlohmann::ordered_json to_json() const override;
    };

    ////////////////////////////////////////////////////////////////////////////////
    /// ConstantExprType - Enumeration of constant literal types.
    ///
    /// Defines the possible literal types that a constant expression node can hold,
    /// such as integers, doubles, strings, booleans, nulls, placeholders, and special
    /// values like max/min sentinels.
    ///
    /// Example usage:
    ///   CET_INT         // Integer literal like 42
    ///   CET_STRING      // String literal like 'hello'
    ///   CET_PLACE_HOLDER // Placeholder for prepared statements, e.g., '?'
    ////////////////////////////////////////////////////////////////////////////////

    struct IntConstantExpr;
    struct DoubleConstantExpr;
    struct BitConstantExpr;
    struct HexConstantExpr;
    struct StringConstantExpr;
    struct BoolConstantExpr;
    struct NullConstantExpr;
    struct PlaceholderConstantExpr;
    struct MaxValueConstantExpr;
    struct MinValueConstantExpr;


    ////////////////////////////////////////////////////////////////////////////////
    /// ConstantExpr - Represents a constant literal expression node.
    ///
    /// This struct models literals appearing in SQL expressions, including numeric,
    /// string, boolean, null, placeholders for prepared statements, and special sentinels.
    /// It uses a union to store the literal value efficiently based on its type.
    ///
    /// Example:
    ///   SELECT * FROM tbl WHERE id = 123;         -- LT_INT with int64_val=123
    ///   SELECT * FROM tbl WHERE name = 'Alice';  -- LT_STRING with str_val="Alice"
    ///   SELECT * FROM tbl WHERE active = TRUE;   -- LT_BOOL with bool_val=true
    ///   PREPARE stmt FROM 'SELECT * FROM tbl WHERE id = ?'; -- LT_PLACE_HOLDER
    ////////////////////////////////////////////////////////////////////////////////

    struct ConstantExpr : public DispatchExpr {
        const pb::ast::ConstantExprType literal_type;

        union {
            bool bool_val;
            int64_t int64_val;
            double double_val;
            String str_val;
        } _u;

        mutable pb::ast::ConstantExprType placeholder_literal_type = pb::ast::CET_INT;
        mutable int placeholder_id = -1; // PreparePlanner and PlanCache

        String row_str;

        ConstantExpr(pb::ast::ConstantExprType c) : DispatchExpr(pb::ast::ExprNodeType::ENT_CONSTANT_EXPR, pb::ast::ENC_CLAUSE),
                                                  literal_type(c) {
            row_str = nullptr;
            _u.str_val = nullptr;
        }

        nlohmann::ordered_json to_json() const override;

        virtual void print() const override;

        virtual void to_stream(std::ostream &os) const override;

        virtual std::string to_string() const override;

        virtual void find_placeholder(std::unordered_set<int> &placeholders) override;

        /// Factory functions to create specific constant expressions from strings or values.
        static IntConstantExpr *make_int(const char *str, turbo::Arena &arena);

        static DoubleConstantExpr *make_double(const char *str, turbo::Arena &arena);

        static BitConstantExpr *make_bit(const char *str, size_t len, turbo::Arena &arena);

        static HexConstantExpr *make_hex(const char *str, size_t len, turbo::Arena &arena);

        static StringConstantExpr *make_string(const char *str, turbo::Arena &arena);

        static StringConstantExpr *make_string(String value, turbo::Arena &arena);

        static BoolConstantExpr *make_true(turbo::Arena &arena);

        static BoolConstantExpr *make_false(turbo::Arena &arena);

        static NullConstantExpr *make_null(turbo::Arena &arena);

        static PlaceholderConstantExpr *make_place_holder(int place_holder_id, turbo::Arena &arena);

        static MaxValueConstantExpr *make_maxvalue(turbo::Arena &arena);

        static MinValueConstantExpr *make_minvalue(turbo::Arena &arena);

    };

    struct IntConstantExpr : public ConstantExpr {
        IntConstantExpr() : ConstantExpr(pb::ast::CET_INT), value(_u.int64_val) {
        }

        int64_t &value;
    };

    struct DoubleConstantExpr : public ConstantExpr {
        DoubleConstantExpr() : ConstantExpr(pb::ast::CET_DOUBLE), value(_u.double_val) {
        }

        double &value;
    };

    struct BitConstantExpr : public ConstantExpr {
        BitConstantExpr() : ConstantExpr(pb::ast::CET_BIT), value(_u.str_val) {
        }

        String &value;
    };

    struct HexConstantExpr : public ConstantExpr {
        HexConstantExpr() : ConstantExpr(pb::ast::CET_HEX), value(_u.str_val) {
        }

        String &value;
    };

    struct StringConstantExpr : public ConstantExpr {
        StringConstantExpr() : ConstantExpr(pb::ast::CET_STRING), value(_u.str_val) {
        }

        String &value;
    };

    struct BoolConstantExpr : public ConstantExpr {
        BoolConstantExpr() : ConstantExpr(pb::ast::CET_BOOL), value(_u.bool_val) {
        }

        bool &value;
    };

    struct NullConstantExpr : public ConstantExpr {
        NullConstantExpr() : ConstantExpr(pb::ast::CET_NULL) {
        }
    };

    struct PlaceholderConstantExpr : public ConstantExpr {
        PlaceholderConstantExpr() : ConstantExpr(pb::ast::CET_PLACE_HOLDER) {
        }
    };

    struct MaxValueConstantExpr : public ConstantExpr {
        MaxValueConstantExpr() : ConstantExpr(pb::ast::CET_MAXVALUE) {
        }
    };

    struct MinValueConstantExpr : public ConstantExpr {
        MinValueConstantExpr() : ConstantExpr(pb::ast::CET_MINVALUE) {
        }
    };

    ////////////////////////////////////////////////////////////////////////////////
    /// RowExpr - Represents a row expression, typically used for tuples or
    /// multi-column expressions.
    ///
    /// This struct models expressions involving a collection of sub-expressions
    /// grouped together in parentheses. It can represent a row of values or
    /// composite expressions in SQL, like SELECT (a, b, c) FROM ....
    ///
    /// Example SQL 1:
    ///   SELECT (id, name, age) FROM users;
    ///   This represents a row expression with sub-expressions for columns
    ///   id, name, and age. Here, the row expression holds multiple column
    ///   references grouped together, represented by `sub_exprs = [id, name, age]`.
    ///
    /// Example SQL 2:
    ///   INSERT INTO my_table (a, b, c) VALUES (1, 'Alice', 30);
    ///   Here, the row expression models the values `(1, 'Alice', 30)`, with
    ///   `sub_exprs = [1, 'Alice', 30]`, where each element corresponds to
    ///   a constant value.
    ////////////////////////////////////////////////////////////////////////////////

    struct RowExpr : public DispatchExpr {
        RowExpr() : DispatchExpr(pb::ast::ExprNodeType::ENT_ROW_EXPR, pb::ast::ENC_CLAUSE) {
        }

        virtual void print() const override {
            std::cout << "row_expr, size:" << sub_exprs.size() << std::endl;
        }

        virtual void to_stream(std::ostream &os) const override {
            os << "(";
            for (int i = 0; i < sub_exprs.size(); i++) {
                os << sub_exprs[i];
                if (i != sub_exprs.size() - 1) {
                    os << ", ";
                }
            }
            os << ")";
        }

        nlohmann::ordered_json to_json() const override;

        /// Columns involved in the row expression, e.g., for multi-column selects.
        Vector<RangeVar *> columns;

        /// Sub-expressions forming the row, e.g., values or expressions inside parentheses.
        Vector<DispatchExpr *> sub_exprs;
    };
} // namespace cantor::parser
